package com.ruoyi.query.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.utils.DictUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.query.QueryColumnUtils;
import com.ruoyi.query.QueryUtils;
import com.ruoyi.query.entity.Query;
import com.ruoyi.query.entity.QueryDtl;
import com.ruoyi.query.entity.ReturnQuery;
import com.ruoyi.query.entity.TableQueryColumn;
import com.ruoyi.query.mapper.QueryMapper;
import com.ruoyi.query.service.QueryDtlService;
import com.ruoyi.query.service.QueryService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * <p>
 * 动态查询 服务实现类
 * </p>
 *
 * @author XiaShiLong
 * @since 2021-03-25
 */
@Service
public class QueryServiceImpl extends ServiceImpl<QueryMapper, Query> implements QueryService {

    private final QueryDtlService queryDtlService;

    private final static String QUERY_TYPE = "dict_query_type";

    @Autowired
    public QueryServiceImpl(QueryDtlService queryDtlService) {
        this.queryDtlService = queryDtlService;
    }

    /**
     * 重写保存
     *
     * @param query <see>Query</see>
     * @return boolean
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean save(Query query) {
        query.setType(1);
        return save(query, QueryUtils.key(query.getClassPath(), query.getUserId()));
    }

    /**
     * 管理员新增
     *
     * @param query <see>Query</see>
     * @return boolean
     */
    @Override
    @Transactional
    public boolean adminSave(Query query) {
        query.setType(0);
        return save(query, QueryUtils.adminKey(query.getClassPath()));
    }

    /**
     * 管理员删除
     *
     * @param query <see>Query</see>
     * @return boolean
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean adminRemove(Query query) {
        QueryUtils.removeAdmin(query);
        this.removeById(query.getId());
        return queryDtlService.removeByQueryId(query.getId());
    }

    /**
     * 管理员修改
     *
     * @param query <see>Query</see>
     * @return boolean
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean adminUpdate(Query query) {
        this.updateById(query);
        boolean b = queryDtlService.updateBatchById(query.getDetailList());
        QueryUtils.updateAdmin(query);
        return b;
    }

    /**
     * 管理员分页查询
     *
     * @param page  页码
     * @param size  每页数量
     * @param query <see>Query</see>
     * @return Page
     */
    @Override
    public List<Query> pageQuery(int page, int size, Query query) {
        return this.getBaseMapper().getAllQuery(query);
    }

    /**
     * 用户删除
     *
     * @param query <see>Query</see>
     * @return boolean
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean userRemove(Query query) {
        QueryUtils.removeUser(query);
        this.removeById(query.getId());
        return queryDtlService.removeByQueryId(query.getId());
    }

    //重写批量删除
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean removeByIds(Collection<? extends Serializable> idList) {
        this.getBaseMapper().deleteBatchIds(idList);
        return queryDtlService.removeByQueryId(idList);
    }

    /**
     * 保存
     *
     * @param query <see>Query</see>
     * @param key   redisKey
     */
    private boolean save(Query query, String key) {
        this.getBaseMapper().insert(query);
        query.getDetailList().forEach(
                q -> q.setQueryId(query.getId())
        );
        boolean b = queryDtlService.saveBatch(query.getDetailList());
        QueryUtils.setCache(key, Collections.singletonList(query));
        return b;
    }

    /**
     * 获取当前对象查询属性
     *
     * @param clz    要查询的对象
     * @param menuId 菜单id
     * @return <see>ReturnSelect</see>
     */
    public ReturnQuery getQuery(Class<?> clz, Long menuId) {
        return ReturnQuery.builder()
                .defaultSelect(getDefault(clz, SecurityUtils.getUserId(), menuId))
                .adminQueryList(QueryUtils.getCacheAdmin(menuId, clz.getName()))
                .userQueryList(QueryUtils.getCacheUser(menuId, clz.getName()))
                .allQueryType(DictUtils.getDictCache(QUERY_TYPE))
                .build();
    }

    /**
     * 根据菜单id和用户id查询
     *
     * @param menuId 菜单id
     * @return List
     */
    @Override
    public List<Query> getByMenuIdAndUserId(Long menuId) {
        return this.getBaseMapper().getByMenuIdAndUserId(menuId, SecurityUtils.getUserId());
    }

    /**
     * 根据菜单id和类型查询
     *
     * @param menuId 菜单id
     * @param type   类型(0系统,1用户)
     * @return List
     */
    @Override
    public List<Query> getByMenuIdAndType(Long menuId, Integer type) {
        return this.getBaseMapper().getByMenuIdAndType(menuId, type);
    }

    /**
     * 获取默认查询列表
     *
     * @param clz    要查询的对象
     * @param userId 当前用户id
     * @param menuId 当前菜单id
     * @return <see>SelectConditions</see>
     */
    private Query getDefault(Class<?> clz, Long userId, Long menuId) {
        List<TableQueryColumn> tableQueryColumnList = QueryColumnUtils.getCache(menuId);
        Query query = null;
        if (!tableQueryColumnList.isEmpty()) {
            AtomicInteger index = new AtomicInteger(0);
            query = Query.builder()
                    .classPath(clz.getName())
                    .userId(userId)
                    .detailList(
                            tableQueryColumnList.stream()
                                    .map(
                                            t -> QueryDtl.builder()
                                                    .columnName(t.getAttributeName())
                                                    .columnNameCh(t.getNameCh())
                                                    .tableColumnName(t.getColumnName())
                                                    .tableName(t.getTableName())
                                                    .columnType(t.getType())
                                                    .sort(index.getAndIncrement())
                                                    .hovId(t.getHovId())
                                                    .build()
                                    ).collect(Collectors.toList())
                    )
                    .build();
        }
        return query;
    }

}
